using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using OpenComposite.Base.Designer;
using OpenComposite.Repository.Designer;
using OpenComposite.Repository.Properties;
using OpenComposite.EII.Repository;

namespace OpenComposite.EII.Designer.BUSView
{
	public class BUSActivitySymbol : Symbol, IRepositoryItemSymbol
	{
		#region Initialization
		public BUSActivitySymbol()
		{
			init();
		}
		private void init()
		{
			this.BeginUpdate();

			this.Text = "Activity";

			this.Size = new Size(100, 40);
			this.MinimumSize = new Size(70, 30);

			this.NameTextBox.Remove();
			//Rectangle rTxt = this.ClientRectangle;
			//rTxt.Inflate(-2,-2);
			//this.NameTextBox.AutoSize = false;
			//this.NameTextBox.Bounds = rTxt;
			//this.NameTextBox.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
			//this.NameTextBox.TextAlign = HorizontalAlignment.Center;

			this.Border = BorderType.Ellipse;
			this.BorderWidth = 2;
			this.BorderColor = Color.CornflowerBlue;
			this.BackBrushMode = BackgroundBrushMode.LinearGradient;
			this.BackColor = Color.White;
			this.BackColor2 = Color.CornflowerBlue;
			this.BackLinearGradientMode = LinearGradientMode.ForwardDiagonal;

			this.ContextMenuStrip.Items.Clear();
			ToolStripMenuItem mi = new ToolStripMenuItem("Subscription Mapping...",
									   Resources.bmp_mapping,
									   new EventHandler(this.SubscriptionMapping_Click));
			mi.ImageTransparentColor = Color.Magenta;
			mi.Name = "Map";
			this.ContextMenuStrip.Items.Add(mi);
			ToolStripSeparator ts0 = new ToolStripSeparator();
			ts0.Name = "sepIO";
			this.ContextMenuStrip.Items.Add(ts0);
			this.ContextMenuStrip.Items.Add("Show Input Business Object...", null, new EventHandler(ShowInputBO_Click)).Name = "ShowIn";
			this.ContextMenuStrip.Items.Add("Show Output Business Object...", null, new EventHandler(ShowOutputBO_Click)).Name = "ShowOut";
			ToolStripSeparator ts1 = new ToolStripSeparator();
			ts1.Name = "sepDelete";
			this.ContextMenuStrip.Items.Add(ts1);
			this.ContextMenuStrip.Items.Add("Delete...", Resources.ico_delete_16x.ToBitmap(),
				new EventHandler(Delete_Click)).Name = "Delete";
			this.ContextMenuStrip.Opening += new CancelEventHandler(ContextMenuStrip_Opening);

			_ptPublishAnchor = Point.Empty;
			_ptSubscribeAnchor = Point.Empty;
			_routePublish = null;
			_routeSubscribe = null;
			_wait = new AutoResetEvent(false);
			_timer = new System.Timers.Timer();
			_timer.AutoReset = true;
			_timer.Interval = 1000;
			_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
			_timer.Start();

			this.EndUpdate();
		}

		void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			if ( Form.ModifierKeys == Keys.Control ) {
				_wait.Set();
			}
		}

		AutoResetEvent _wait = null;
		System.Timers.Timer _timer = null;

		#endregion

		#region Public Members

		#region Properties
		// new
		public BUSSymbol BUS
		{
			get
			{
				if ( _bus == null && this.DesignerViewControl != null ) {
					foreach ( DesignerControl dc in this.DesignerViewControl.DesignerControls ) {
						if ( dc is BUSSymbol ) {
							_bus = (BUSSymbol)dc;
							break;
						}
					}
				}
				return _bus;
			}
			set
			{
				_bus = value;
				if ( value != null && _isProcessReply ) {
					this.Location = new Point(value.Location.X, value.Location.Y + 20);
				}
			}
		}

		[Description("Capability")]
		public Repository.Verb Verb
		{
			get { return this.LogicalActivity.Verb; }
		}
		public Repository.Operation Operation
		{
			get { return this.LogicalActivity.GetAssignedOperation(); }
		}
		public Repository.WorkflowEvent WorkflowEvent
		{
			get { return this.LogicalActivity.GetWorkflowEvent(); }
		}
		public Repository.WorkflowMethod WorkflowMethod
		{
			get { return this.LogicalActivity.GetWorkflowMethod(); }
		}
		public Repository.LogicalActivity LogicalActivity
		{
			get { return _logact; }
			set
			{
				if ( _logact != value ) {
					_logact = value;
					OnLogicalActivityChanged();
				}
			}
		}
		private bool _isProcessReply;
		public bool IsProcessReply
		{
			get { return _isProcessReply; }
			set
			{
				_isProcessReply = value;
				if ( value ) {
					this.MinimumSize = new Size(30, 30);
					this.Size = new Size(30, 30);
				}
			}
		}

		public bool CanChangeSubscription
		{
			get
			{
				return this.LogicalActivity.LogicalActivityType != LogicalActivityType.LogicalInput &&
					 this.LogicalActivity.LogicalActivityType != LogicalActivityType.RuleEvaluator;
			}
		}
		public bool HasSubscriptions
		{
			get
			{
				return ( this.SubscribedBusinessObjects != null &&
						 this.SubscribedBusinessObjects.Count > 0 );
			}
		}
		public NamedBusinessObjectCollection SubscribedBusinessObjects
		{
			get
			{
				if ( _routeSubscribe == null ) {
					return null;
				} else {
					return _routeSubscribe.Document.NamedBusinessObjects;
				}
			}
		}

		// override
		public override bool CanResize
		{
			get
			{
				return false;
			}
		}
		public override bool CanDrag
		{
			get
			{
				return false;
			}
		}
		public override bool CanMove
		{
			get
			{
				return !IsProcessReply;
			}
		}
		public Point SubscribeDocLocation
		{
			get { return new Point(Location.X, Location.Y + 35); }
		}

		public override string Text
		{
			get
			{
				return base.Text;
			}
			set
			{
				base.Text = value;
			}
		}

		#endregion

		#region Events
		#endregion

		#region Methods

		// override
		public override void Paint(PaintEventArgs pe)
		{
			if ( this.WorkflowMethod != null && this.IsProcessReply ) {

			} else {
				Rectangle rTxt = this.GetPaintClientArea();
				rTxt.Inflate(-2, -2);
				using ( StringFormat sf = new StringFormat(StringFormat.GenericDefault) ) {
					sf.Alignment = StringAlignment.Center;
					sf.LineAlignment = StringAlignment.Center;
					string text = this.Text;
					pe.Graphics.DrawString(this.Text, this.Font, this.ForeBrush, rTxt, sf);
				}
				bool bDrawStatusOk = false;
				if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.Notification ) {
					BUSViewController bvc = this.DesignerViewControl.DesignController as BUSViewController;
					if ( Helpers.IsNotificationConfigurated(bvc.Workflow, this.LogicalActivity) ) {
						bDrawStatusOk = true;
					}
				} else if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.DataAggregator ) {
					if ( this.HasSubscriptions ) {
						if ( this.LogicalActivity != null &&
							 this.LogicalActivity.InputXslt != null ) {
							bDrawStatusOk = true;
						}
					}
				} else if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.RuleEvaluator ) {
					if ( this.HasSubscriptions ) {
						bDrawStatusOk = true;
					}
				} else {
					if ( this.HasSubscriptions ) {
						if ( this.LogicalActivity != null && this.LogicalActivity.InputXslt != null ) {
							bDrawStatusOk = true;
						}
					} else {
						if ( this.LogicalActivity != null && this.LogicalActivity.InputBusinessObject == null ) {
							bDrawStatusOk = true;
						}
					}
				}
				if ( bDrawStatusOk )
					pe.Graphics.DrawImage(Resources.status_ok, rTxt.Right, rTxt.Top);

				base.Paint(pe);
			}
		}
		public override void PaintBackground(PaintEventArgs pe)
		{
			if ( this.WorkflowMethod != null && this.IsProcessReply ) {
				// draw workflow start
				Rectangle r = this.GetPaintBounds();
				Rectangle rstart = new Rectangle(r.Left, r.Top, 30, 30);
				pe.Graphics.DrawEllipse(Pens.Blue, rstart);
				using ( LinearGradientBrush brush = new LinearGradientBrush(rstart, Color.White, Color.CornflowerBlue, LinearGradientMode.ForwardDiagonal) ) {
					pe.Graphics.FillEllipse(brush, rstart);
				}
			} else {
				base.PaintBackground(pe);
			}
		}
		public override void ReadXml(XmlReader reader)
		{
			RepositoryService repSvc = (RepositoryService)this.GetService(typeof(RepositoryService));
			Debug.Assert(repSvc != null);

			while ( reader.Read() ) {
				switch ( reader.Name ) {
					case "LogicalActivity":
						if ( reader.MoveToAttribute("id") && reader.ReadAttributeValue() )
							this.LogicalActivity = repSvc.GetItem(ItemType.LogicalActivity,
																 int.Parse(reader.Value), false) as LogicalActivity;
						if ( reader.MoveToAttribute("isProcessReply") && reader.ReadAttributeValue() )
							this.IsProcessReply = bool.Parse(reader.Value);
						if ( this.LogicalActivity == null )
							throw new RepositoryItemDeletedException();
						break;
					default:
						ReadStandardProperties(reader);
						break;
				}
			}
		}
		public override void WriteXml(XmlWriter writer)
		{
			WriteStandardProperties(writer);
			if ( this.LogicalActivity != null ) {
				writer.WriteStartElement("LogicalActivity");
				writer.WriteAttributeString("id", this.LogicalActivity.ID.ToString());
				writer.WriteAttributeString("name", this.LogicalActivity.Name);
				writer.WriteAttributeString("isProcessReply", this.IsProcessReply.ToString());
				writer.WriteEndElement();
			}
		}

		// Drag'n'Drop
		public override bool IsDropAllowed(object obj, Point location, MouseButtons button)
		{
			if ( obj == null ) {
				return false;
			} else if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.LogicalMethodCall ) {
				WorkflowMethod wm = this.WorkflowMethod;
				BUSDocumentSymbol busdoc = obj as BUSDocumentSymbol;
				NamedBusinessObject bobj = obj as NamedBusinessObject;
				if ( busdoc != null ) {
					return wm.InputBusinessObject == busdoc.SelectedBusinessObject;
				} else if ( bobj != null ) {
					if ( bobj.BusinessObject.WorkflowField != null ) {
						return wm.InputBusinessObject == bobj.BusinessObject.WorkflowField.BusinessObject;
					} else {
						return wm.InputBusinessObject == bobj.BusinessObject;
					}
				}
				return false;
			} else {
				return this.IsDropAllowed(obj.GetType(), location, button);
			}
		}
		public override bool IsDropAllowed(Type type, Point location, MouseButtons button)
		{
			return this.CanChangeSubscription;
		}
		public override void DropObject(object obj, Point location, MouseButtons button)
		{
			if ( !this.CanChangeSubscription )
				return;

			BUSDocumentSymbol doc = obj as BUSDocumentSymbol;
			NamedBusinessObject bobj = obj as NamedBusinessObject;
			if ( doc != null ) {
				if ( _routeSubscribe == null ) {
					_routeSubscribe = this.DesignerViewControl.AddRoute(this.BUS, this) as BUSSubscribeRoute;
					_routeSubscribe.Removed += new EventHandler(_routeSubscribe_Removed);
				}
				Debug.Assert(_routeSubscribe != null);
				if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.LogicalMethodCall ) {
					_routeSubscribe.Document.NamedBusinessObjects.Clear();
					this.LogicalActivity.InputVariableName = bobj.Name;
				}
				foreach ( string key in doc.NamedBusinessObjects.Names ) {
					if ( !_routeSubscribe.Document.NamedBusinessObjects.Contains(key) ) {
						_routeSubscribe.Document.NamedBusinessObjects.Add(key, doc.NamedBusinessObjects[key], null);
					}
				}
				refreshRoutes();
			} else if ( bobj != null ) {
				if ( _routeSubscribe == null ) {
					_routeSubscribe = this.DesignerViewControl.AddRoute(this.BUS, this) as BUSSubscribeRoute;
					_routeSubscribe.Removed += new EventHandler(_routeSubscribe_Removed);
				}
				Debug.Assert(_routeSubscribe != null);
				if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.LogicalMethodCall ) {
					_routeSubscribe.Document.NamedBusinessObjects.Clear();
					this.LogicalActivity.InputVariableName = bobj.Name;
				}
				if ( !_routeSubscribe.Document.NamedBusinessObjects.Contains(bobj) ) {
					_routeSubscribe.Document.NamedBusinessObjects.Add(bobj);
				}
				refreshRoutes();
			}

			if ( _routeSubscribe != null && _routeSubscribe.Document != null && IsProcessReply ) {
				_routeSubscribe.Document.Location = this.SubscribeDocLocation;
			}
		}

		public override object GetDragObject(Point location, MouseButtons button)
		{
			return null;
		}

		// Create Route Start / End
		public override bool CreateRouteStart(DesignerControl controlEnd, out IConnector connector, out System.Drawing.Drawing2D.LineCap cap, out System.Drawing.Drawing2D.CustomLineCap customcap, out RouteDockDirection dockStart, out RouteDockDirection dockEnd, out bool useStartConnectorAsRouteStart)
		{
			if ( IsProcessReply ) {
			}
			// document Published
			bool ok = false;

			cap = LineCap.RoundAnchor;
			customcap = null;
			useStartConnectorAsRouteStart = true;
			connector = this;

			BUSSymbol bus = controlEnd as BUSSymbol;
			if ( bus != null ) {
				if ( controlEnd.Top > this.Bottom ) {
					dockStart = RouteDockDirection.Bottom;
					dockEnd = RouteDockDirection.Top;
				} else {
					dockStart = RouteDockDirection.Top;
					dockEnd = RouteDockDirection.Bottom;
				}
				ok = true;
			} else {
				dockStart = RouteDockDirection.Bottom;
				dockEnd = RouteDockDirection.Top;
			}
			return ok;
		}
		public override bool CreateRouteEnd(DesignerControl controlStart, out IConnector connector, out System.Drawing.Drawing2D.LineCap cap, out System.Drawing.Drawing2D.CustomLineCap customcap, out RouteDockDirection dockStart, out RouteDockDirection dockEnd, out bool useEndConnectorAsRouteEnd)
		{
			if ( IsProcessReply ) {
			}
			// document Subscribed
			bool ok = false;

			cap = LineCap.Custom;
			customcap = new AdjustableArrowCap(5.0f, 5.0f, true);
			useEndConnectorAsRouteEnd = true;
			connector = this;

			BUSSymbol bus = controlStart as BUSSymbol;
			if ( bus != null ) {
				if ( controlStart.Top < this.Bottom ) {
					dockStart = IsProcessReply ? RouteDockDirection.Right : RouteDockDirection.Bottom;
					dockEnd = IsProcessReply ? RouteDockDirection.Left : RouteDockDirection.Top;
				} else {
					dockStart = IsProcessReply ? RouteDockDirection.Left : RouteDockDirection.Top;
					dockEnd = IsProcessReply ? RouteDockDirection.Right : RouteDockDirection.Bottom;
				}
				ok = true;
			} else {
				dockStart = IsProcessReply ? RouteDockDirection.Right : RouteDockDirection.Bottom;
				dockEnd = IsProcessReply ? RouteDockDirection.Left : RouteDockDirection.Top;
			}
			return ok;
		}

		// Get Route Start / End Point
		public override Point GetRouteStart(RouteDockDirection dock, Route route)
		{
			// Publish
			Point pt = base.GetRouteStart(dock, route);
			if ( _routePublish != null && _routeSubscribe != null ) {
				pt.X += 20;
			}
			return pt;
		}
		public override Point GetRouteEnd(RouteDockDirection dock, Route route)
		{
			// Subscribe
			if ( IsProcessReply ) {
				if ( BUS != null ) {
					return new Point(BUS.Location.X + 26, BUS.Location.Y + 45);
				} else {
					return base.GetRouteEnd(dock, route);
				}
			} else {
				Point pt = base.GetRouteEnd(dock, route);
				if ( _routePublish != null && _routeSubscribe != null ) {
					pt.X -= 20;
				}
				return pt;
			}
		}
		#endregion

		#endregion

		#region Protected Members

		#region Properties
		internal BUSViewController BUSViewController
		{
			get
			{
				if ( this.DesignerViewControl == null ) return null;
				return this.DesignerViewControl.DesignController as BUSViewController;
			}
		}
		#endregion

		#region Methods
		// new
		protected virtual void OnLogicalActivityChanged()
		{
			this.BeginUpdate();
			if ( this.LogicalActivity == null ) {
				this.Text = "No Logical Activity";
				return;
			}
			this.Text = getName();
			if ( this.Verb != null ) {
				//this.Text = this.Verb.Name;
				if ( this.Verb.OutputBusinessObjectID > 0 ) {
					//if ( _routePublish == null ) {
					//    _routePublish = this.DesignerViewControl.AddRoute(this, this.BUS) as BUSPublishRoute;
					//    _routePublish.Removed += new EventHandler(_routePublish_Removed);
					//}
					//_routePublish.Document.BusinessObjects.Clear();
					//if ( this.Verb.OutputBusinessObjectID > 0 )
					//    _routePublish.Document.BusinessObjects.Add(this.Verb.OutputBusinessObject);
				} else if ( _routePublish != null ) {
					_routePublish.Remove();
				}
			} else if ( this.Operation != null ) {
				this.Border = BorderType.RoundedRectangle;
				this.BorderWidth = 1;
				this.BorderFixedRoundedBorderDiameter = 20;
				this.BackLinearGradientMode = LinearGradientMode.Horizontal;
				//this.Text = this.Operation.Name;
				if ( this.Operation.OutputBusinessObjectId > 0 ) {
					//if ( _routePublish == null ) {
					//    _routePublish = this.DesignerViewControl.AddRoute(this, this.BUS) as BUSPublishRoute;
					//    _routePublish.Removed += new EventHandler(_routePublish_Removed);
					//}
					//_routePublish.Document.BusinessObjects.Clear();
					//if ( this.Verb.OutputBusinessObjectID > 0 )
					//    _routePublish.Document.BusinessObjects.Add(this.Verb.OutputBusinessObject);
				} else if ( _routePublish != null ) {
					_routePublish.Remove();
				}
			} else if ( this.WorkflowEvent != null ) {
				if ( _routePublish != null && this.WorkflowEvent.BusinessObjectID <= 0 )
					_routePublish.Remove();
			} else if ( this.WorkflowMethod != null ) {
				if ( _routePublish != null && this.WorkflowMethod.OutputBusinessObjectID <= 0 )
					_routePublish.Remove();
			} else if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.DataAggregator ) {
				// 
			} else if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.RuleEvaluator ) {
				//this.Text = this.LogicalActivity.Name;
			} else if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.Undefined ) {
				//this.Remove();
				//return;
				//this.Text = "Activity";
				if ( _routePublish != null )
					_routePublish.Remove();

			} else {
				//this.Remove();
				//return;
				if ( _routePublish != null )
					_routePublish.Remove();
			}
			switch ( this.LogicalActivity.LogicalActivityType ) {
				case LogicalActivityType.DataAggregator:
					this.Border = BorderType.RoundedRectangle;
					this.BorderColor = Color.YellowGreen;
					this.BorderWidth = 1;
					this.BorderFixedRoundedBorderDiameter = 20;
					this.BackLinearGradientMode = LinearGradientMode.ForwardDiagonal;
					this.BackColor = Color.YellowGreen;
					this.BackColor2 = Color.White;
					break;
				case LogicalActivityType.LogicalCapability:
					this.Border = BorderType.RoundedRectangle;
					this.BorderColor = Color.CornflowerBlue;
					this.BorderWidth = 1;
					this.BorderFixedRoundedBorderDiameter = 20;
					this.BackLinearGradientMode = LinearGradientMode.ForwardDiagonal;
					this.BackColor = Color.White;
					this.BackColor2 = Color.CornflowerBlue;
					break;
				case LogicalActivityType.LogicalOperation:
					this.Border = BorderType.RoundedRectangle;
					this.BorderColor = Color.CornflowerBlue;
					this.BorderWidth = 1;
					this.BorderFixedRoundedBorderDiameter = 20;
					this.BackLinearGradientMode = LinearGradientMode.Horizontal;
					this.BackColor = Color.White;
					this.BackColor2 = Color.CornflowerBlue;
					break;
				case LogicalActivityType.RuleEvaluator:
					this.Border = BorderType.RoundedRectangle;
					this.BorderColor = Color.DarkRed;
					this.BorderWidth = 1;
					this.BorderFixedRoundedBorderDiameter = 20;
					this.BackLinearGradientMode = LinearGradientMode.ForwardDiagonal;
					this.BackColor = Color.OrangeRed;
					this.BackColor2 = Color.White;
					break;
				case LogicalActivityType.LogicalInput:
					this.Border = BorderType.RoundedRectangle;
					this.BorderColor = Color.YellowGreen;
					this.BorderWidth = 1;
					this.BorderFixedRoundedBorderDiameter = 20;
					this.BackLinearGradientMode = LinearGradientMode.Vertical;
					this.BackColor = Color.YellowGreen;
					this.BackColor2 = Color.White;
					break;
				case LogicalActivityType.LogicalMethodCall:
					this.Border = BorderType.RoundedRectangle;
					this.BorderColor = Color.FromArgb(208, 105, 208);
					this.BorderWidth = 1;
					this.BorderFixedRoundedBorderDiameter = 20;
					this.BackLinearGradientMode = LinearGradientMode.Vertical;
					this.BackColor = Color.FromArgb(208, 105, 208);
					this.BackColor2 = Color.White;
					break;
				case LogicalActivityType.Notification:
					this.Border = BorderType.RoundedRectangle;
					this.BorderColor = Color.FromArgb(193, 144, 29);
					this.BorderWidth = 1;
					this.BorderFixedRoundedBorderDiameter = 20;
					this.BackLinearGradientMode = LinearGradientMode.Horizontal;
					this.BackColor = Color.Goldenrod;
					this.BackColor2 = Color.Cornsilk;
					break;
				default:
					this.Border = BorderType.RoundedRectangle;
					this.BorderColor = Color.Red;
					this.BorderWidth = 1;
					this.BorderFixedRoundedBorderDiameter = 20;
					this.BackLinearGradientMode = LinearGradientMode.ForwardDiagonal;
					this.BackColor = Color.Red;
					this.BackColor2 = Color.White;
					break;
			}

			refreshRoutes();
			this.EndUpdate();
		}

		protected override void OnLostFocus(EventArgs e)
		{
			base.OnLostFocus(e);
			_bAutoLocate = false;
		}

		protected override void OnSizeChanged(EventArgs e)
		{
			autoLocate();
			base.OnSizeChanged(e);
		}

		private bool _bAutoLocate = false;
		private void autoLocate()
		{
			try {
				if ( this.DesignerViewControl == null || this.DesignerViewControl.DesignerControls == null ) return;
				foreach ( DesignerControl ctrl in this.DesignerViewControl.DesignerControls.ControlsWithoutRoutes.ToArray() ) {
					if ( ctrl == this ) continue;
					if ( ctrl is Route ) continue;
					if ( ctrl is BUSDocumentSymbol ) continue;
					if ( ctrl is BUSSymbol ) continue;
					Rectangle thisBounds = this.Bounds;
					thisBounds.Inflate(70, 30);
					if ( ctrl.Bounds.IntersectsWith(thisBounds) ) {
						//if ( ctrl.Bounds.Left == this.Bounds.Left ) {
						//    DesignerControl ctrlToMove = this.Bounds.Top > ctrl.Bounds.Top ? this : ctrl;
						//    DesignerControl otherCtrl = ctrlToMove == this ? ctrl : this;
						//    _bAutoLocate = true;
						//    ctrlToMove.Location = new Point(otherCtrl.Location.X, otherCtrl.Bounds.Bottom + 30);
						//    //_bAutoLocate = false;
						//} else {
						//    DesignerControl ctrlToMove = this.Bounds.Right > ctrl.Bounds.Right ? this : ctrl;
						//    DesignerControl otherCtrl = ctrlToMove == this ? ctrl : this;
						//    _bAutoLocate = true;
						//    ctrlToMove.Location = new Point(otherCtrl.Bounds.Right + 45, ctrlToMove.Location.Y);
						//    //_bAutoLocate = false;
						//}
						//_wait.WaitOne();
						if ( this.Bounds.Right <= ctrl.Bounds.Right ) {
							ctrl.Location = new Point(this.Bounds.Right + 70, ctrl.Location.Y);
						} else {
							ctrl.Location = new Point(this.Bounds.Left - 70 - ctrl.Bounds.Width, ctrl.Location.Y);
						}
					}
				}
			} catch {
			}
			return;
		}

		// override
		protected override void OnLocationChanged(EventArgs e)
		{
			if ( _isInLocationChanged )
				return;

			if ( this.BUS != null && !this.IsProcessReply ) {
				_isInLocationChanged = true;
				this.BeginUpdate();
				// replace if to near to bus
				int xPos = this.Left;
				int yPos = this.Top;
				if ( this.Left < this.BUS.ActivitiesMinX )
					xPos = this.BUS.ActivitiesMinX;
				if ( this.Bottom > ( this.BUS.Top - cBUSGap ) && this.Bottom < this.BUS.Bottom )
					yPos = this.BUS.Top - cBUSGap - this.Height;
				else if ( this.Top > this.BUS.Top && this.Top < ( this.BUS.Bottom + cBUSGap ) )
					yPos = this.BUS.Bottom + cBUSGap;
				this.Location = new Point(xPos, yPos);

				// switch route docking
				bool isAbove = ( this.Bottom < this.BUS.Top );
				if ( _routePublish != null ) {
					_routePublish.StartDockDirection = isAbove ? RouteDockDirection.Bottom : RouteDockDirection.Top;
					_routePublish.EndDockDirection = isAbove ? RouteDockDirection.Top : RouteDockDirection.Bottom;
				}
				if ( _routeSubscribe != null ) {
					_routeSubscribe.StartDockDirection = isAbove ? RouteDockDirection.Top : RouteDockDirection.Bottom;
					_routeSubscribe.EndDockDirection = isAbove ? RouteDockDirection.Bottom : RouteDockDirection.Top;
				}
				this.EndUpdate();
				_isInLocationChanged = false;
			}
			try {
				if ( !_bAutoLocate ) {
					autoLocate();
				}
			} finally {
				_bAutoLocate = false;
			}

			base.OnLocationChanged(e);
		}
		#endregion

		#endregion

		#region Private Members

		#region Constants
		private int cBUSGap = 100;
		#endregion

		#region Variables
		private bool _isInLocationChanged = false;

		Point _ptPublishAnchor;
		Point _ptSubscribeAnchor;

		BUSPublishRoute _routePublish;
		BUSSubscribeRoute _routeSubscribe;

		Repository.LogicalActivity _logact;

		BUSSymbol _bus;

		#endregion

		#region Methods

		private void refreshRoutes()
		{
			if ( _routePublish != null ) _routePublish.RefreshRoute();
			if ( _routeSubscribe != null ) _routeSubscribe.RefreshRoute();
		}

		private string getName()
		{
			string text = "";
			if ( BUSViewController != null && this.LogicalActivity != null ) {
				OpenComposite.Workflow.Interfaces.ITextActivity act =
					   Helpers.GetActivityByLogicalActivityID(
					   Helpers.GetRootActivity(BUSViewController.Workflow) as System.Workflow.ComponentModel.CompositeActivity,
					   this.LogicalActivity.ID) as OpenComposite.Workflow.Interfaces.ITextActivity;
				if ( act != null ) {
					if ( !string.IsNullOrEmpty(act.Text) ) {
						text = act.Text;
					}
				}
			}
			if ( text == "" ) {
				if ( this.LogicalActivity != null ) text = this.LogicalActivity.Name;
				else if ( this.Verb != null ) text = this.Verb.Name;
				else if ( this.Operation != null ) text = this.Operation.Name;
				else if ( this.WorkflowEvent != null ) text = this.WorkflowEvent.Name;
				else if ( this.WorkflowMethod != null ) text = this.WorkflowMethod.Name;
			}

			return text;
		}

		private void doSubscriptionMapping()
		{
			if ( _routeSubscribe == null ||
				 _routeSubscribe.Document.NamedBusinessObjects.Count == 0 ||
				 this.LogicalActivity == null )
				return;
			if ( this.LogicalActivity.InputBusinessObject == null ) {
				MessageBox.Show("This logical capability has not an input contract.", "Subscription Mapping", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				return;
			}

			Mapping.DoSubscriptionMapping(
				_routeSubscribe.Document.NamedBusinessObjects,
				this.LogicalActivity,
				this.LogicalActivity.InputBusinessObject);

		}
		private void doDataAggregatorMapping()
		{
			if ( _routeSubscribe == null || _routeSubscribe.Document.NamedBusinessObjects.Count == 0 )
				return;

			BusinessObject boOutput = this.LogicalActivity.GetOutputBusinessObject();
			if ( boOutput == null || boOutput.Schema == null ) {
				MessageBox.Show("No Output Business Object Available.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
				return;
			}
			Mapping.DoSubscriptionMapping(
				_routeSubscribe.Document.NamedBusinessObjects,
				this.LogicalActivity,
				boOutput);
		}
		#endregion

		#region Event Handlers

		private void _routePublish_Removed(object sender, EventArgs e)
		{
			_routePublish.Removed -= new EventHandler(this._routePublish_Removed);
			_routePublish = null;
			refreshRoutes();
		}
		private void _routeSubscribe_Removed(object sender, EventArgs e)
		{
			_routeSubscribe.Removed -= new EventHandler(this._routeSubscribe_Removed);
			_routeSubscribe = null;
			refreshRoutes();
		}

		private void ContextMenuStrip_Opening(object sender, CancelEventArgs e)
		{
			if ( this.LogicalActivity != null &&
				 ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.RuleEvaluator ) ) {
				e.Cancel = true;
				return;
			}
			if ( this.LogicalActivity == null ||
				 this.LogicalActivity.LogicalActivityType == LogicalActivityType.Undefined ) {
				this.ContextMenuStrip.Items["sepDelete"].Visible = true;
				this.ContextMenuStrip.Items["Delete"].Visible = true;
			} else {
				this.ContextMenuStrip.Items["sepDelete"].Visible = false;
				this.ContextMenuStrip.Items["Delete"].Visible = false;
			}
			if ( this.LogicalActivity != null ) {
				if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.DataAggregator ) {
					this.ContextMenuStrip.Items["Map"].Text = "Aggregation Mapping...";
					this.ContextMenuStrip.Items["sepIO"].Visible = false;
					this.ContextMenuStrip.Items["ShowIn"].Visible = false;
					this.ContextMenuStrip.Items["ShowOut"].Visible = false;
				} else if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.Notification ) {
					this.ContextMenuStrip.Items["Map"].Text = "Notification Configuration...";
					this.ContextMenuStrip.Items["sepIO"].Visible = false;
					this.ContextMenuStrip.Items["ShowIn"].Visible = false;
					this.ContextMenuStrip.Items["ShowOut"].Visible = false;
				} else {
					this.ContextMenuStrip.Items["Map"].Text = "Subscription Mapping...";
					this.ContextMenuStrip.Items["sepIO"].Visible = true;
					this.ContextMenuStrip.Items["ShowIn"].Visible = true;
					this.ContextMenuStrip.Items["ShowOut"].Visible = true;
				}
			}
			//if ( this.LogicalActivity.LogicalActivityType != LogicalActivityType.DataAggregator )
			//    e.Cancel = true;
		}
		private void SubscriptionMapping_Click(object sender, EventArgs e)
		{
			if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.LogicalCapability ||
				 this.LogicalActivity.LogicalActivityType == LogicalActivityType.LogicalOperation ) {
				//doInputMappingPhysical();
				doSubscriptionMapping();
			} else if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.DataAggregator ) {
				doDataAggregatorMapping();
			} else if ( this.LogicalActivity.LogicalActivityType == LogicalActivityType.Notification ) {
				BUSViewController bvc = this.DesignerViewControl.DesignController as BUSViewController;
				if ( bvc != null ) {
					bvc.Save();
					Helpers.ConfigNotification(bvc.Workflow, this.LogicalActivity);
				}
			}
			this.Invalidate();
		}
		private void Delete_Click(object sender, EventArgs e)
		{
			this.Remove();
		}

		private void ShowInputBO_Click(object sender, EventArgs e)
		{
			if ( this.LogicalActivity == null || this.LogicalActivity.InputBusinessObject == null ) return;
			Helpers.ShowBusinessObjectTree(this.LogicalActivity.InputBusinessObject,
				string.Format("{0} (Input of {1})", this.LogicalActivity.InputBusinessObject.Name, this.LogicalActivity.Name));

		}
		private void ShowOutputBO_Click(object sender, EventArgs e)
		{
			if ( this.LogicalActivity == null || this.LogicalActivity.OutputBusinessObject == null ) return;
			Helpers.ShowBusinessObjectTree(this.LogicalActivity.OutputBusinessObject,
				string.Format("{0} (Output of {1})", this.LogicalActivity.OutputVariableName, this.LogicalActivity.Name));
		}

		#endregion

		#endregion


		#region IRepositoryItemSymbol Members

		public bool SaveHierarchy
		{
			get { return false; }
		}

		public bool IsReference
		{
			get
			{
				return true;
			}
			set
			{
			}
		}

		public bool CanBeMainControl
		{
			get { return false; }
		}

		public IRepositoryItem RepositoryItem
		{
			get
			{
				return this.LogicalActivity;
			}
			set
			{
				this.LogicalActivity = value as LogicalActivity;
			}
		}

		public void Load(int idRepository, int idDomain)
		{
			if ( this.LogicalActivity == null ) {
				this.Remove();
				return;
			}
			// set the text for this symbol
			if ( this.LogicalActivity != null ) {

			} else if ( this.Verb != null ) this.Text = this.Verb.Name;
			else if ( this.Operation != null ) this.Text = this.Operation.Name;
			else if ( this.WorkflowEvent != null ) this.Text = this.WorkflowEvent.Name;
			else if ( this.WorkflowMethod != null ) this.Text = this.WorkflowMethod.Name;

			// set published documents for this activity
			if ( this.Verb != null && this.Verb.OutputBusinessObjectID > 0 ) {
				if ( _routePublish == null ) {
					_routePublish = this.DesignerViewControl.AddRoute(this, this.BUS) as BUSPublishRoute;
					_routePublish.Removed += new EventHandler(_routePublish_Removed);
				}
				_routePublish.Document.NamedBusinessObjects.Clear();
				_routePublish.Document.NamedBusinessObjects.Add(LogicalActivity.OutputVariableName, LogicalActivity.OutputBusinessObject, LogicalActivity);
			} else if ( this.Operation != null && this.Operation.OutputBusinessObjectId > 0 ) {
				if ( _routePublish == null ) {
					_routePublish = this.DesignerViewControl.AddRoute(this, this.BUS) as BUSPublishRoute;
					_routePublish.Removed += new EventHandler(_routePublish_Removed);
				}
				_routePublish.Document.NamedBusinessObjects.Clear();
				_routePublish.Document.NamedBusinessObjects.Add(LogicalActivity.OutputVariableName, LogicalActivity.OutputBusinessObject, LogicalActivity);
			} else if ( this.WorkflowEvent != null && this.WorkflowEvent.BusinessObjectID > 0 ) {
				if ( _routePublish == null ) {
					_routePublish = this.DesignerViewControl.AddRoute(this, this.BUS) as BUSPublishRoute;
					_routePublish.Removed += new EventHandler(_routePublish_Removed);
				}
				_routePublish.Document.NamedBusinessObjects.Clear();
				_routePublish.Document.NamedBusinessObjects.Add(LogicalActivity.OutputVariableName, LogicalActivity.OutputBusinessObject, LogicalActivity);
			} else if ( this.WorkflowMethod != null && this.WorkflowMethod.OutputBusinessObjectID > 0 ) {
				if ( _routePublish == null ) {
					_routePublish = this.DesignerViewControl.AddRoute(this, this.BUS) as BUSPublishRoute;
					_routePublish.Removed += new EventHandler(_routePublish_Removed);
				}
				_routePublish.Document.NamedBusinessObjects.Clear();
				_routePublish.Document.NamedBusinessObjects.Add(LogicalActivity.OutputVariableName, LogicalActivity.OutputBusinessObject, LogicalActivity);
			} else if ( this.LogicalActivity != null && this.LogicalActivity.OutputBusinessObjectID > 0 ) {
				if ( _routePublish == null ) {
					_routePublish = this.DesignerViewControl.AddRoute(this, this.BUS) as BUSPublishRoute;
					_routePublish.Removed += new EventHandler(_routePublish_Removed);
				}
				_routePublish.Document.NamedBusinessObjects.Clear();
				_routePublish.Document.NamedBusinessObjects.Add(LogicalActivity.OutputVariableName, LogicalActivity.OutputBusinessObject, LogicalActivity);
			} else if ( _routePublish != null ) {
				_routePublish.Remove();
			}
			NamedBusinessObjectCollection bos = this.LogicalActivity.GetSubscribedBusinessObjects();
			if ( bos != null && bos.Count > 0 ) {
				if ( _routeSubscribe == null ) {
					_routeSubscribe = this.DesignerViewControl.AddRoute(this.BUS, this) as BUSSubscribeRoute;
					Debug.Assert(_routeSubscribe != null);
					_routeSubscribe.Removed += new EventHandler(_routeSubscribe_Removed);
				}
				_routeSubscribe.Document.BeginUpdate();
				_routeSubscribe.Document.NamedBusinessObjects.Clear();
				for ( int i = 0; i < bos.Count; i++ ) {
					if ( !_routeSubscribe.Document.NamedBusinessObjects.Contains(bos[i]) ) {
						_routeSubscribe.Document.NamedBusinessObjects.Add(bos.Names[i], bos.BusinessObjects[i], bos.LogicalActivities[i]);
					}
				}
				_routeSubscribe.Document.EndUpdate();
				refreshRoutes();
			} else if ( this.LogicalActivity.InputBusinessObjectID <= 0 ) {
				if ( _routeSubscribe != null ) {
					_routeSubscribe.Remove();
				}
			}

			if ( _routeSubscribe != null && _routeSubscribe.Document != null && IsProcessReply ) {
				_routeSubscribe.Document.Location = this.SubscribeDocLocation;
			}
		}

		public bool Save(int idRepository, int idDomain)
		{
			if ( _routeSubscribe != null ) {
				this.LogicalActivity.SetSubscribedBusinessObjects(_routeSubscribe.Document.NamedBusinessObjects);
			}
			return true;
		}

		public bool Delete(bool bAsk)
		{
			return false;
		}

		#endregion
	}
}
